#include "stdafx.h"
#include <Windows.h>

#include <Gdiplus.h>
#pragma comment(lib,"Gdiplus.lib")

#include <shellapi.h>

class GdiPlusInit
{
public:
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiPlusInit()
	{
		Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	}
	~GdiPlusInit()
	{
		Gdiplus::GdiplusShutdown(gdiplusToken);
	}
};

GdiPlusInit Instance;

int GetEncoderClsid(LPCWSTR format, CLSID *pClsid)
{
	UINT     num = 0;
	UINT     size = 0;

	Gdiplus::ImageCodecInfo*   pImageCodecInfo = NULL;

	Gdiplus::GetImageEncodersSize(&num, &size);
	if (size == 0)
		return   -1;     //   Failure 

	pImageCodecInfo = (Gdiplus::ImageCodecInfo*)malloc(size);
	if (pImageCodecInfo == NULL)
		return   -1;     //   Failure 

	GetImageEncoders(num, size, pImageCodecInfo);

	for (UINT j = 0; j < num; ++j)
	{
		if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return   j;     //   Success 
		}
	}

	free(pImageCodecInfo);
	return   -1;     //   Failure 
}

Gdiplus::Bitmap* ScaleImage(Gdiplus::Bitmap *source, int width, int height)
{
	Gdiplus::Rect zoomRect(0, 0, width, height);
	Gdiplus::Bitmap* pImageScale = new Gdiplus::Bitmap(zoomRect.Width, zoomRect.Height, PixelFormat32bppARGB);
	Gdiplus::Graphics graphicsScale(pImageScale);
	Gdiplus::TextureBrush brush(source);
	graphicsScale.ScaleTransform((Gdiplus::REAL)((Gdiplus::REAL)zoomRect.Width / (Gdiplus::REAL)source->GetWidth()),
		(Gdiplus::REAL)((Gdiplus::REAL)zoomRect.Height / (Gdiplus::REAL)source->GetHeight()));
	graphicsScale.FillRectangle(&brush, zoomRect);
	return pImageScale;
}

HICON GetIconFromFile(LPCTSTR szImageFileName)
{
	SHFILEINFO sfi;
	if (SUCCEEDED(SHGetFileInfo(szImageFileName, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES)))
	{
		if (sfi.hIcon)
		{
			return sfi.hIcon;
		}
	}

	return NULL;
}

BOOL GetIconPNG(LPCTSTR szImageFileName, PUCHAR *ppData, SIZE_T *pLength)
{
	BOOL bSuccess = FALSE;
	CLSID encoderClsid;

	SHFILEINFO sfi;
	if (SUCCEEDED(SHGetFileInfo(szImageFileName, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES)))
	{
		if (sfi.hIcon)
		{
			if (-1 != GetEncoderClsid(L"image/png", &encoderClsid))
			{
				Gdiplus::Bitmap icon(sfi.hIcon);
				Gdiplus::Bitmap *newIcon = ScaleImage(&icon, 64, 64);
				IStream* pStream = NULL;
				if (SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pStream)))
				{
					if (newIcon && Gdiplus::Ok == newIcon->Save(pStream, &encoderClsid, NULL))
					{
						LARGE_INTEGER move = { 0 };
						ULARGE_INTEGER newPos = { 0 };
						ULONG ulRealSize = 0;
						if (SUCCEEDED(pStream->Seek(move, STREAM_SEEK_END, &newPos)))
						{
							SIZE_T ulLength = 0;
							PUCHAR pData = NULL;

							ulLength = newPos.LowPart;
							pData = (PUCHAR)malloc(ulLength);

							if (pData)
							{
								if (SUCCEEDED(pStream->Seek(move, STREAM_SEEK_SET, NULL)) && SUCCEEDED(pStream->Read(pData, ulLength, &ulRealSize)))
								{
									*ppData = pData;
									*pLength = ulLength;
									bSuccess = TRUE;
								}
								else
								{
									free(pData);
								}
							}
						}
					}
					pStream->Release();
				}
				if (newIcon)
					delete newIcon;
			}

			DestroyIcon(sfi.hIcon);
		}
	}

	return bSuccess;
}